/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package czStvDpds.graphics3D.gui;

import czStvDpds.graphics3D.Scene;
import czStvDpds.logging.Logging;
import java.util.ArrayList;

/**
 * Vec, ktera totalne zastresuje cele GUI. Funguje na principu CardLayout - je
 * mozne nastavit, ktery z vlozenych komponentu se bude zobrazovat. Vzdy
 * existuje nekolik superContaineru, kazdemu prislusi nejaka scena. Staticke
 * metody maji proto parametr sceneIndex, ktery rozhoduje, s jakym kontejnerem
 * se bude pracovat (pouzivejte konstanty).
 *
 * @author Ondra
 */
public class SuperContainer implements LCardContainer {
    //---------------------STATICKA CAST---------------------------------------

    private static SuperContainer[] containers = {null, null};
    public static final int GAME_MENU = 0, TITLE_MENU = 1;
    private static int activeSceneIndex = -1;

    /**
     * vrati aktualni superkontejner, pokud existuje. To se hodi, pokud do nej
     * budete chtit pridat nejake komponenty nebo tak neco :D
     *
     * @return
     */
    public static LCardContainer getAsContainer(int sceneIndex) {
        return containers[sceneIndex];
    }

    public static Scene getActiveScene() {
        return activeSceneIndex == -1 ? null : containers[activeSceneIndex].getScene();
    }

    public static int getActiveSceneIndex() {
        return activeSceneIndex;
    }

    private static void setActiveSceneIndex(int newActiveSceneIndex) {
        activeSceneIndex = newActiveSceneIndex;
        //schovavani scen si resi grafika podle svych modu
    }

    /**
     * vytvori vlastne nove GUI - novy superContainer. Smaze to puvodni, pokud
     * neco existovalo.
     *
     * @return neco, co se da pouzit jako swingovy panel
     */
    public static LCardContainer create(int sceneIndex, Scene scene) {
        containers[sceneIndex] = new SuperContainer(scene);
        setActiveSceneIndex(sceneIndex);
        return containers[sceneIndex];
    }

    public static void switchContainer(int sceneIndex) {
        if (containers[sceneIndex] != null) {
            setActiveSceneIndex(sceneIndex);
        } else {
            throw new IllegalArgumentException("Requested container does not exist.");
        }
    }

    /**
     * Kompletne vymaze kontejner urceny indexem. Na jeho misto dosadi novy,
     * prazdny, ale pouzije pro nej starou scenu.
     */
    public static void resetContainer(int sceneIndex) {
        containers[sceneIndex].hideAllChildren();
        containers[sceneIndex] = new SuperContainer(containers[sceneIndex].getScene());
        activeSceneIndex = -1;
    }
    /**
     * Smaze kontejner urceny indexem. Na jeho misto da <code>null</code>
     * @param sceneIndex 
     */
    public static void clearContainer(int sceneIndex) {
        containers[sceneIndex].hideAllChildren();
        containers[sceneIndex] = null;
        activeSceneIndex = -1;
    }
    //--------------------NESTATICKA CAST-----------------------------------
    private ArrayList<LComponent> components;
    private float reduceRatio;
    private ComponentRelativeSize containerSize;
    private float screenWidth, screenHeight;
    private LComponent showingComponent;
    private Scene scene;

    private SuperContainer(Scene scene) {
        super();
        this.scene = scene;
        components = new ArrayList();
        reduceRatio = 0.8f;
        screenWidth = scene.getUnitRelativeWidth();
        screenHeight = scene.getUnitRelativeHeight();
        containerSize = new ComponentRelativeSize(reduceRatio * screenHeight, reduceRatio * screenWidth);
        showingComponent = null;
    }

    /**
     * prida component
     *
     * @param component
     * @param index
     */
    @Override
    public void addComponent(LComponent component, int index) {
        components.add(index, component);
        component.setParent(this);
        showComponent(component);
        recalculate();
    }

    /**
     * nastavi "okraje". Cislo zadava, na jakem procentu daneho prostoru bude
     * kontejner pracovat. 1.0f = cely prostor.
     *
     * @param newRatio
     */
    public void setReduceRatio(float newRatio) {
        reduceRatio = newRatio;
        containerSize.setHeight(reduceRatio * screenHeight);
        containerSize.setWidth(reduceRatio * screenWidth);
        recalculate();
    }

    @Override
    public void removeComponent(LComponent component) {
        if (component == showingComponent) {
            if (!components.isEmpty()) {
                showComponent(0);
            } else {
                showingComponent = null;
            }
        }
        components.remove(component);
        recalculate();
    }

    private void recalculate() {
        screenWidth = scene.getUnitRelativeWidth();
        screenHeight = scene.getUnitRelativeHeight() /*0.75f*/;
        
        containerSize.setHeight(reduceRatio * screenHeight);
        containerSize.setWidth(reduceRatio * screenWidth);
        
        if (showingComponent != null) {
            
            //overeni zda je reduceRatio aplikovatelne
            ComponentPixelSize areaSize = containerSize.getPixelSize();
            ComponentPixelSize minSize = showingComponent.getMinSize();
            if (minSize.getHeight() > areaSize.getHeight()) {
                reduceRatio = (float) minSize.getHeight() / (float) scene.getHeight();
                containerSize.setHeight(reduceRatio * screenHeight);
                containerSize.setWidth(reduceRatio * screenWidth);
                areaSize = containerSize.getPixelSize();
            }
            if (minSize.getWidth() > areaSize.getWidth()) {
                reduceRatio = (float) minSize.getWidth() / (float) scene.getWidth();
                containerSize.setHeight(reduceRatio * screenHeight);
                containerSize.setWidth(reduceRatio * screenWidth);
//                areaSize = containerSize.getPixelSize();
            }

            //nastaveni pozice komponente
            float compWidth = containerSize.getWidth();
            float compHeight = containerSize.getHeight();
            float compX = (screenWidth - compWidth) / 2;
            float compY = (screenHeight - compHeight) / 2;
            showingComponent.setBounds(compX, compY, compWidth, compHeight);
        }
    }

    @Override
    public void childChanged(LComponent child) {
        if (child == showingComponent) {
            recalculate();
        }
    }

    @Override
    public void showComponent(int index) {
        if (index >= components.size()) {
            throw new IllegalArgumentException("Index out of Bounds");
        }
        for (LComponent component : components) {
            component.setVisible(false);
        }
        showingComponent = components.get(index);
        recalculate();
        showingComponent.setVisible(true);
    }

    @Override
    public void showComponent(LComponent component) {
        if (components.contains(component)) {
            showComponent(components.indexOf(component));
        } else {
            throw new IllegalArgumentException("Component not recongnized.");
        }
    }

    @Override
    public void removeComponent(int index) {
        removeComponent(components.get(index));
    }

    public Scene getScene() {
        return scene;
    }

    public void hideAllChildren() {
        for (LComponent component : components) {
            component.setVisible(false);
        }
    }
}
